/**
 * @file gt_obj_pos.c
 * @author yongg
 * @brief Set object position function
 * @version 0.1
 * @date 2022-06-15 14:34:36
 * @copyright Copyright (c) 2014-2022, Company Genitop. Co., Ltd.
 */

/* include --------------------------------------------------------------*/
#include "gt_obj_pos.h"
#include "../hal/gt_hal_disp.h"
#include "../widgets/gt_obj.h"
#include "../others/gt_log.h"
#include "gt_disp.h"
#include "gt_indev.h"

/* private define -------------------------------------------------------*/



/* private typedef ------------------------------------------------------*/



/* static variables -----------------------------------------------------*/



/* macros ---------------------------------------------------------------*/



/* static functions -----------------------------------------------------*/



/* global functions / API interface -------------------------------------*/

void gt_area_copy(gt_area_st * dst, gt_area_st * src){
    dst->x = src->x;
    dst->y = src->y;
    dst->w = src->w;
    dst->h = src->h;
}

bool gt_obj_is_visible(gt_obj_st * obj){
    gt_disp_st * disp = gt_disp_get_default();
    if( !disp ){
        GT_LOGW( GT_LOG_TAG_GUI, "disp is null" );
    }
    if( GT_INVISIBLE == obj->visible ){
        return false;
    }

    gt_area_st area_obj, area_disp;

    gt_area_copy( &area_disp, &disp->area_disp );
    gt_area_copy( &area_obj, &obj->area );

    if( (area_obj.x + area_obj.w) < area_disp.x ){
        return false;
    }

    if( (area_obj.y + area_obj.h) < area_disp.y ){
        return false;
    }

    if( area_obj.x > (area_disp.x + area_disp.w) ){
        return false;
    }
    if( area_obj.y > (area_disp.y + area_disp.h) ){
        return false;
    }
    return true;
}

bool gt_obj_check_visible(gt_obj_st * obj, gt_area_st area)
{
    gt_area_st area_obj, area_disp;
    gt_area_copy(&area_disp, &area);
    gt_area_copy(&area_obj, &obj->area);

    if( (area_obj.x + area_obj.w) < area_disp.x ){
        return false;
    }

    if( (area_obj.y + area_obj.h) < area_disp.y ){
        return false;
    }

    if( area_obj.x > (area_disp.x + area_disp.w) ){
        return false;
    }
    if( area_obj.y > (area_disp.y + area_disp.h) ){
        return false;
    }
    return true;
}

void gt_obj_get_valid_area(gt_obj_st * obj, gt_area_st * area_act, gt_area_st *area_valid)
{
	gt_area_st area_disp, area_obj;

    gt_area_copy(&area_disp, area_act);
    gt_area_copy(&area_obj, &obj->area);

    #define __X1(area)    (area.x)
    #define __X2(area)    (area.x+area.w)
    #define __Y1(area)    (area.y)
    #define __Y2(area)    (area.y+area.h)


    if( __X1(area_disp) <= __X1(area_obj) ){
        area_valid->x = 0;
    }else{
        area_valid->x = __X1(area_disp) - __X1(area_obj);
    }

    if( __Y1(area_disp) <= __Y1(area_obj) ){
        area_valid->y = 0;
    }else{
        area_valid->y = __Y1(area_disp) - __Y1(area_obj);
    }

    if( __X2(area_disp) >= __X2(area_obj) ){
        if( __X1(area_disp) <= __X1(area_obj) ){
            area_valid->w = area_obj.w;
        }else{
            area_valid->w = __X2(area_obj) - __X1(area_disp);
        }
    }else{
        if( __X1(area_disp) <= __X1(area_obj) ){
            area_valid->w = __X2(area_disp) - __X1(area_obj);
        }else{
            area_valid->w = area_disp.w;
        }
    }

    if( __Y2(area_disp) >= __Y2(area_obj) ){
        if( __Y1(area_disp) <= __Y1(area_obj) ){
            area_valid->h = area_obj.h;
        }else{
            area_valid->h = __Y2(area_obj) - __Y1(area_disp);
        }
    }else{
		if( __Y1(area_disp) <= __Y1(area_obj) ){
            area_valid->h = __Y2(area_disp) - __Y1(area_obj);
        }else{
            area_valid->h = area_disp.h;
        }
	}

    return;
}


bool gt_obj_check_is_clicked( gt_obj_st * obj, gt_point_st * point ){
    bool ret = false;
    if( (point->x >= obj->area.x) && (point->x <= (obj->area.x + obj->area.w)) ){
        if( (point->y >= obj->area.y) && (point->y <= (obj->area.y + obj->area.h)) ){
            ret = true;
        }
    }
    return ret;
}

static gt_obj_st * _gt_obj_foreach_clicked(gt_obj_st * parent, gt_point_st * point){
    int idx = 0;
    gt_obj_st * obj_clicked = NULL, * obj_temp = NULL;
    while( idx < parent->cnt_child ){
        if( 0 != parent->child[idx]->cnt_child ){
            obj_temp = _gt_obj_foreach_clicked(parent->child[idx], point);
            if( obj_temp && GT_VISIBLE == obj_temp->visible ){
                obj_clicked = obj_temp;
                return obj_clicked;
            } 
        }
        if( gt_obj_check_is_clicked(parent->child[idx], point) ){
            if( parent->child[idx] && GT_VISIBLE == parent->child[idx]->visible ){
                obj_clicked = parent->child[idx];
            }
        }
        idx++;
    }
    return obj_clicked;
}

gt_obj_st * gt_find_clicked_obj_by_point(gt_obj_st * parent, gt_point_st * point){
    // uint8_t idx = 0;
    gt_obj_st * obj_clicked = parent, * obj_temp = NULL;
    gt_area_st * area = gt_disp_get_area_act();
    gt_point_st _point = {
        .x = point->x + area->x,
        .y = point->y + area->y
    };
    obj_temp = _gt_obj_foreach_clicked(parent, &_point);
    if( obj_temp ){
        obj_clicked = obj_temp;
    }
    return obj_clicked;

#if 0
	// old func: no foreach all obj
    while( idx < parent->cnt_child ){
        if( gt_obj_check_is_clicked(parent->child[idx], &_point) ){
            if( parent->child[idx] ){
                obj_clicked = parent->child[idx];
            }
        }
        idx++;
    }
    return obj_clicked;
#endif
}

bool gt_obj_check_scr(gt_obj_st * obj)
{
    gt_obj_st * scr_now = gt_disp_get_scr();

    gt_obj_st * scr_obj = obj->parent;
    while( scr_obj->parent ){
        scr_obj = scr_obj->parent;
    }
    if( scr_now == scr_obj ){
        return true;
    }else{
        return false;
    }
}

/**
 * @brief set obj process point data
 *
 * @param obj obj
 * @param point point ptr
 */
void _gt_obj_set_process_point(gt_obj_st * obj, gt_point_st * point){
    obj->process_attr.point.x = point->x;
    obj->process_attr.point.y = point->y;
}

/**
 * @brief set obj process scroll xy
 *
 * @param obj
 * @param x_scroll
 * @param y_scroll
 */
void _gt_obj_set_process_scroll_xy(gt_obj_st * obj, gt_size_t x_scroll, gt_size_t y_scroll)
{
    obj->process_attr.x_scroll = x_scroll;
    obj->process_attr.y_scroll = y_scroll;
}

/**
 * @brief Get the point of the clicked obj
 *
 * @param obj click obj
 * @param point_phy point data
 * @param point_ret point data
 */
void gt_obj_get_click_point_by_phy_point(gt_obj_st * obj, gt_point_st * point_phy, gt_point_st * point_ret)
{
    gt_point_st point;
    point.x = point_phy->x;
    point.y = point_phy->y;

    // cal last point in virt screen pos
    gt_area_st * area_act_p = gt_disp_get_area_act();
    gt_area_st area_act;
    gt_area_copy(&area_act, area_act_p);

    point.x += area_act.x;
    point.y += area_act.y;

    point_ret->x = point.x - obj->area.x;
    point_ret->y = point.y - obj->area.y;
}
/* end ------------------------------------------------------------------*/
